package biz

import (
	"fmt"
	"log"
	"server/base"
	"server/base/db"
	"server/biz/proto"
	"strings"
	"text/template"
	"time"
)

type OrderRaw struct {
	Id        int
	No        string
	UserId    int
	Platform  string
	Sysv      string
	Cap       float64
	Size      float64
	Dst       string
	BotId     string
	Status    int
	Progress  int
	Total     int
	Games     int
	CreatedAt int
}

func (o *OrderRaw) TL() *proto.Order {
	r := &proto.Order{
		Id:        o.Id,
		No:        o.No,
		Platform:  o.Platform,
		Cap:       o.Cap,
		Size:      o.Size,
		Games:     o.Games,
		Status:    o.Status,
		CreatedAt: o.CreatedAt,
	}
	if o.Total > 0 {
		r.Progress = float64(o.Progress) * 100 / float64(o.Total)
	}
	return r
}

func GetOrder(id int) *OrderRaw {
	if id == 0 {
		return nil
	}
	var o = &OrderRaw{}
	db.Replica.QueryRowx(`select no, user_id, platform, sysv, cap, size, dst, bot_id, status, progress, total, games, created_at from orders where id=?`, id).Scan(
		&o.No, &o.UserId, &o.Platform, &o.Sysv, &o.Cap, &o.Size, &o.Dst, &o.BotId, &o.Status, &o.Progress, &o.Total, &o.Games, &o.CreatedAt)
	o.Id = id
	return o
}

func GenerateOrderNo(platform string) string {
	t := time.Now().UnixMilli()
	pre := "A"
	if platform == "pc" {
		pre = "B"
	}
	return fmt.Sprintf("%s%d", pre, t)
}

func SumPkgs(pkg_ids []int) float64 {
	if len(pkg_ids) == 0 {
		return 0
	}
	ids := base.JoinInts(pkg_ids)
	var out float64
	sql := fmt.Sprintf("select coalesce(sum(sizea),0) from package where id in (%s)", ids)
	db.Replica.Get(&out, sql)
	return out
}

func CountGames(order_id int) int {
	var n int
	db.Replica.Get(&n, `select count(distinct op.game_id) from order_pkg op
where op.order_id=?
`, order_id)
	return n
}

func UpdateOrderGames(order_id int) {
	n := CountGames(order_id)
	db.Primary.Exec(`update orders set games=? where id=?`, n, order_id)
}

// 增加游戏统计次数
func IncrOrderAdds(order_id int) {
	db.Primary.Exec(`update game g set g.adds=g.adds+1
where g.id in (
	select distinct op.game_id from orders o
	inner join order_pkg op on op.order_id=o.id
	where o.id=?
)`, order_id)
}

func GetOrderGames(order_id int) []string {
	var out []string
	if order_id == 0 {
		return out
	}
	rows := db.Replica.Query(`select g.name from orders o
inner join order_pkg op on op.order_id=o.id
inner join game g on g.id=op.game_id
where o.id=?
group by g.id`, order_id)
	defer rows.Close()
	for rows.Next() {
		var name string
		rows.Scan(&name)
		out = append(out, name)
	}
	return out
}

// 在硬盘根目录生成订单txt
func GenerateOrderTxt(o *OrderRaw) string {
	if o.Dst == "" {
		log.Println("SaveOrderTxt warning: Dst is empty", o.No)
		return ""
	}
	names := GetOrderGames(o.Id)
	total := len(names)
	out := strings.Join(names, "\n")

	platform := o.Platform
	order_tpl := GetSetting(platform, "order_tpl")
	if order_tpl == "" {
		return ""
	}
	tpl, err := template.New("foo").Parse(order_tpl)
	if err != nil {
		log.Println("tpl err:", err)
		return ""
	}
	capa := fmt.Sprintf("%.02f", o.Cap)
	sizea := fmt.Sprintf("%.02f", o.Size)
	data := &struct {
		List     string
		Total    int
		No       string
		Platform string
		Cap      string
		Size     string
	}{
		List:     out,
		Total:    total,
		No:       o.No,
		Platform: platform,
		Cap:      capa,
		Size:     sizea,
	}
	//o.Dst = "/root/d"
	//filename := fmt.Sprintf("%s/%s.txt", o.Dst, o.No)
	//f, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
	//if err != nil {
	//	log.Println("save err:", err)
	//	return
	//}
	//defer f.Close()
	b := &strings.Builder{}
	tpl.Execute(b, data)
	return b.String()
}

func CreateOrder(o *OrderRaw, pkg_ids []int) {
	tx := db.Primary.Begin()
	defer tx.Rollback()
	if o.No == "" {
		o.No = GenerateOrderNo(o.Platform)
	}
	if o.CreatedAt == 0 {
		o.CreatedAt = int(time.Now().Unix())
	}
	size := SumPkgs(pkg_ids)
	total := len(pkg_ids)
	r := tx.Exec(`insert into orders set no=?, user_id=?, platform=?, sysv=?, cap=?, size=?, dst=?, status=0, total=?, created_at=?`,
		o.No, o.UserId, o.Platform, o.Sysv, o.Cap, size, o.Dst, total, o.CreatedAt)
	id := int(r.LastInsertId())
	o.Id = id
	for _, pkg_id := range pkg_ids {
		tx.Exec(`insert into order_pkg(order_id, pkg_id, game_id, version_id, pkg_name, pkg_size, pkg_src)
select ?, p.id, p.game_id, p.version_id, p.name, p.sizea, p.src from package p where p.id=?
`, id, pkg_id)
	}
	tx.Commit()
	UpdateOrderGames(id)
	IncrOrderAdds(id)
}

func GetOrders(user_id int) []*OrderRaw {
	var out []*OrderRaw
	rows := db.Replica.Query(`select id, no, user_id, platform, sysv, cap, size, dst, status, progress, total, games, created_at from orders 
where user_id=? order by id desc`, user_id)
	if rows == nil {
		return out
	}
	defer rows.Close()
	for rows.Next() {
		var o = &OrderRaw{}
		rows.Scan(&o.Id, &o.No, &o.UserId, &o.Platform, &o.Sysv, &o.Cap, &o.Size, &o.Dst, &o.Status, &o.Progress, &o.Total, &o.Games, &o.CreatedAt)
		out = append(out, o)
	}
	return out
}
